Neural Delay Control — MLP-Modulated Adaptive Delay

Adaptive delay whose per-frame mix and feedback modulation is computed by a hand-designed 30-8-2 Multi-Layer Perceptron (MLP) evaluated entirely inside Praat — no Python, no training data, pure neural architecture running in realtime-like frames.

Author: Shai Cohen Affiliation: Department of Music, Bar-Ilan University, Israel Version: 1.0 (2026) License: MIT License Repo: https://github.com/ShaiCohen-ops/Praat-plugin_AudioTools
Contents:

What this does

This script implements a neural network-controlled adaptive delay effect. Unlike standard delay pedals where mix and feedback are static, this effect modulates these parameters frame-by-frame based on the audio's timbral and temporal characteristics. A 30-8-2 Multi-Layer Perceptron (MLP) processes 30 acoustic features per frame (MFCCs, delta-MFCCs, HNR, voicing, intensity, transients) and outputs two modulation signals that adjust the user's base mix and feedback levels.

What "Neural" means here: The architecture is genuinely neural: 30 input nodes, one hidden layer with 8 ReLU units, and a 2-unit tanh output layer. The forward pass (matrix multiply, bias add, activation) is evaluated for every analysis frame inside Praat. However, the 266 weights are hand-designed, not trained on data. Each hidden unit's weights were manually chosen to respond to specific patterns (HNR detector, transient detector, vocal-formant MFCC detector, etc.). Output weights were selected to approximate a musically useful modulation around the user's base values. The result is a structurally trainable network — you could later expose the weights as a CSV and learn them with Python against your own preference labels — but as delivered, it's a fixed, interpretable neural effect.

Key Features:

Delay engine: The underlying delay is an N-tap exponential decay delay with optional cascaded lowpass filtering (for analog warmth). Each repeat's feedback amount is scaled by feedback_base^repeat, then further modulated frame-by-frame by the MLP's output. The MLP modulates around the user's base values: final mix = clamp(base_mix + 0.4×out₁, 0.05, 0.8), final feedback = clamp(base_feedback + 0.3×out₂, 0.10, 0.7).

Quick start

  1. In Praat, select exactly one Sound object.
  2. Run script…Neural_Delay_Control.praat.
  3. Choose a preset from the dropdown (6 options).
  4. Or select "Manual" and adjust Delay_time_ms, Feedback_base, Mix_base, Number_of_repeats.
  5. Optionally enable lowpass filter and set cutoff (for analog warmth).
  6. Set Frame_step_ms (analysis resolution) and Smooth_ms (control smoothing).
  7. Click OK — script extracts features, runs MLP forward pass, applies adaptive delay, and creates output originalname_neuralMLP_presetname.
Quick tip: Start with Clean Digital for transparent, MLP-modulated repeats. Analog Warmth adds lowpass filtering for tape-like decay. Ambient Wash features long delay (500 ms) and higher feedback for lush textures. Enable Draw_visualization to see the MLP's mix/feedback curves alongside HNR and voicing features.
Important: The MLP runs inside Praat — no Python, no external dependencies. However, MFCC extraction can be slow for long sounds (expect ~10–30 seconds processing time for a 60-second file). The script is fully deterministic — same input + same parameters = same output. The MLP responds to spectral content (MFCCs), so the effect will sound different on speech vs. percussion vs. sustained tones. This is intentional — the network was hand-designed to emphasise timbral variation.

MLP Architecture — 30-8-2

Network equations

Input layer: x ∈ ℝ³⁰ (normalised features per frame)

Hidden layer (ReLU): hⱼ = max(0, b1ⱼ + Σₖ w1[ⱼ,ₖ]·xₖ) — j = 1..8

Output layer (tanh): outₒ = tanh(b2ₒ + Σⱼ w2[ₒ,ⱼ]·hⱼ) — o = 1 (mix), 2 (feedback)

Final modulation: mix = clamp(base_mix + 0.4·out₁, 0.05, 0.8)
feedback = clamp(base_feedback + 0.3·out₂, 0.10, 0.7)

Hidden Units — Hand-Designed Detectors

h₁ HNR detector — positive weight on HNR, bias -0.3. Responds to harmonic content.
h₂ Voicing detector — positive weight on voicing flag, bias -0.4. Activates on pitched frames.
h₃ Transient detector — positive weight on transient_norm, bias -0.3. Responds to attacks.
h₄ Sustained-energy detector — HNR + voicing + intensity, negative on transient. Bias -0.4.
h₅ Vocal-formant MFCC — positive weights on MFCC1-3 (spectral tilt and coarse formants).
h₆ Timbral-change detector — positive weights on |ΔMFCC1..5|. Responds to spectral motion.
h₇ High-band MFCC — positive weights on MFCC8-13. Responds to high-frequency detail.
h₈ Constant bias unit — no weights, bias = +1.0. Always active.
Output weights interpretation: Output 1 (mix modulation) is increased by h₁ (HNR) and h₂ (voicing), strongly decreased by h₃ (transient) and h₆ (timbral change). Output 2 (feedback modulation) follows similar logic but with different scaling. The result: during sustained, harmonic passages, mix and feedback rise (more delay presence). During transients or rapid timbral shifts, both decrease (cleaner attack).

30 Input Features per Frame

Features computed per analysis frame (default step = 20 ms):
[1]–[13]MFCC 1–13 / 30 (normalised spectral envelope coefficients)
[14]–[26]|ΔMFCC 1–13| / 30 (absolute frame-to-frame change)
[27]HNR_norm — Harmonics-to-Noise Ratio normalised 0–1
[28]Voicing — 0 (unvoiced) or 1 (voiced) from Pitch tracking
[29]Intensity_norm — (dB - 60) / 30 + 0.5, clamped to [0,1]
[30]Transient_norm — absolute intensity difference / 20, clamped to [0,1]
MFCC details: 13 Mel-frequency cepstral coefficients capture spectral envelope shape. The script normalises by dividing by 30 to bring values into roughly [-1, 1] range. Delta-MFCCs capture timbral change between consecutive frames — high values indicate spectral motion (e.g., note transitions, consonants, percussive attacks). HNR (Harmonicity) measures periodicity: high = clear pitch, low = noisy.

6 Presets

PresetDelay (ms)Feedback baseMix baseRepeatsFilterCharacter
Clean Digital2500.350.304offTransparent, MLP-modulated repeats.理想
Analog Warmth3000.500.355LP @ 3 kHzWarm, tape-like decay with high-frequency rolloff.
Slapback800.150.452offShort, classic slapback echo.
Rhythmic Dotted3750.450.354LP @ 4.5 kHzDotted eighth feel, rhythmic texture.
Ambient Wash5000.600.406LP @ 2.5 kHzLong, lush, reverb-like decay.
Modulated2000.450.354LP @ 5 kHzMLP modulation emphasised — expressive variation.
Filters: When enabled, each repeat passes through a lowpass Hann band filter. For repeats beyond the second, the cutoff is further reduced (multiply by 0.8) to simulate increased high-frequency damping — characteristic of analog delay units.

Applications

Expressive Delay for Voice

Use case: Singing or speech with delay that responds to timbre — sustains have more presence, consonants remain clean.

Settings: Ambient Wash preset. The MLP will increase mix/feedback during sustained vowels (high HNR, high voicing) and reduce during consonants (transients, timbral change).

Rhythmic Instrument Processing

Use case: Guitar arpeggios or piano phrases where delay density follows note density.

Settings: Rhythmic Dotted preset. The MLP's timbral-change detector (h₆) responds to note transitions, creating a delay that feels "intelligent".

Glitch / Experimental Textures

Use case: Percussion or granular material where the MLP's transient response creates unpredictable modulation.

Settings: Modulated preset with short delay (200 ms). The MLP will rapidly vary mix/feedback on each transient — results can be glitchy, stutter-like, or pulsing.

Workflow: Voice → Ambient Wash

Target: Spoken word or sung phrase.
Settings: Ambient Wash preset, draw_visualization=yes.
Result: Sustained vowels trigger longer, louder repeats (MLP increases mix/feedback). Consonants remain relatively dry. The delay becomes a dynamic shadow of the voice.

Workflow: Drum loop → Modulated Slapback

Target: Drum loop.
Settings: Slapback preset, but with Modulated's MLP response (use Custom: mix_base=0.45, feedback_base=0.15, but the MLP will still react).
Result: Each drum hit triggers a slapback, but the MLP's transient detector (h₃) and timbral-change detector (h₆) will quickly reduce the second and third echoes — creates a "smart" gated slapback.

Troubleshooting:
MLP not modulating enough: Increase Frame_step_ms (lower resolution) or Smooth_ms (more smoothing) to see slower, more noticeable changes. The modulation range is ±0.4 on mix and ±0.3 on feedback from the base values — if base is near extremes, modulation is limited.
Delay sounds static / no modulation: Ensure the input has timbral variation. Pure sine waves or white noise will produce no MFCC/delta-MFCC variation; the network outputs will be near zero. Try speech or music.
Processing is slow: MFCC extraction is the bottleneck. Reduce duration, increase frame_step_ms (e.g., 30 ms), or use a shorter sound.
Understanding the MLP output: Enable visualization — Panel A shows the red (mix) and green (feedback) curves over time. Compare with Panel B (HNR and voicing) to see correlations.

Visualization Panels

When Draw_visualization is enabled, the script produces a comprehensive 8×8 cm picture with:
  • Panel A: MLP control output — red = mix, green = feedback (dashed = user base values)
  • Panel B: Source features — purple = HNR, orange dots = voiced frames
  • Panel C: Zoom overlay (first 500 ms) — original gray, output blue
  • Panel D: Full output waveform with delay tail
  • Panel E: Summary — network architecture, feature set, delay parameters, and stats
Extending the network: The 266 weights are defined as Praat pseudo-arrays (w1[j,k], w2[o,j], biases). To train your own weights, you would need to: (1) export features and target modulation values, (2) train a small MLP in Python (e.g., with PyTorch or scikit-learn), (3) convert the weights back to Praat array assignments. The architecture is deliberately small (266 parameters) to make such experimentation feasible.